#include "scenes/RotateRectangle.h"
#include "app_control/ELDirector.h"
#include "math/ELGeometry.h"
#include "app_control/ELOpenGLView.h"

NS_BEGIN(elloop);

using namespace CELL;

struct Vertex
{
    float2      pos;
    Rgba4Byte   color;
};

struct FAuxiliaryOpenGLContext 
{
	EGLConfig               _config;
	EGLSurface              _surface;
	EGLContext              _context;
	EGLDisplay              _display;
};
FAuxiliaryOpenGLContext AuxiliaryOpenGLContext;
void InitAuxiliaryOpenGLContext()
{
	auto director = Director::getInstance();
	auto glView = director->getGLView();
    assert(glView != nullptr);
    glView->_context;

	const EGLint attirbs[] =
	{
		EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
		EGL_BLUE_SIZE, 8,
		EGL_GREEN_SIZE, 8,
		EGL_RED_SIZE, 8,
		EGL_DEPTH_SIZE, 24,
		EGL_NONE
	};

	EGLint format(0);
	EGLint numConfigs(0);
	EGLint major;
	EGLint minor;

    AuxiliaryOpenGLContext._display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

	eglInitialize(AuxiliaryOpenGLContext._display, &major, &minor);

	eglChooseConfig(AuxiliaryOpenGLContext._display, attirbs, &AuxiliaryOpenGLContext._config, 1, &numConfigs);

	eglGetConfigAttrib(AuxiliaryOpenGLContext._display, AuxiliaryOpenGLContext._config, EGL_NATIVE_VISUAL_ID, &format);

	//_surface = eglCreateWindowSurface(AuxiliaryOpenGLContext._display, AuxiliaryOpenGLContext._config, _hwnd, nullptr);

	EGLint attr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE, EGL_NONE };
    AuxiliaryOpenGLContext._context = eglCreateContext(AuxiliaryOpenGLContext._display, AuxiliaryOpenGLContext._config, glView->_context, attr);

	if (eglMakeCurrent(AuxiliaryOpenGLContext._display, EGL_NO_SURFACE, EGL_NO_SURFACE, AuxiliaryOpenGLContext._context) == EGL_FALSE)
	{
        assert(false);
	}

	//eglQuerySurface(_display, _surface, EGL_WIDTH, &_width);
	//eglQuerySurface(_display, _surface, EGL_HEIGHT, &_height);
	//return true;

}


ProgramId AuxiliaryComiledProgramId = -1;
std::string vsFileName_mt = "shaders/color_rectangle_vs_mt.glsl";
std::string fsFileName_mt = "shaders/color_rectangle_fs_mt.glsl";
ShaderId        _vertexShaderId_mt;
ShaderId        _fragShaderId_mt;
void AuxiliaryCompilerShader()
{
	


	bool error(false);
	do
	{
	

		AuxiliaryComiledProgramId = ShaderHelper::linkProgram(_vertexShaderId_mt, _fragShaderId_mt);
		error = (AuxiliaryComiledProgramId == 0);
		BREAK_IF(error);

	} while (false);
}

bool IsQuitAuxiliaryRHIThread = false;
std::vector<std::function<void()>> QuitAuxiliaryRHITask;
void AuxiliaryRHIThread(Event* InEvent)
{
	if (InEvent)
	{
		while (!IsQuitAuxiliaryRHIThread)
		{
			InEvent->Wait();
			for (auto& Task : QuitAuxiliaryRHITask)
			{
				Task();
			}
			QuitAuxiliaryRHITask.clear();
		}
	}
}

void RotateRectangle::render()
{
	{
		static int Count = 0;
		Count++;
		if (Count == 300)
		{
			QuitAuxiliaryRHITask.push_back(AuxiliaryCompilerShader);
			AuxiliaryRHIThreadEvent.Wakeup();
		}
	}

    using namespace CELL;

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    auto director = Director::getInstance();
    Size s = director->getFrameSize();
    float width = s._width;
    float height = s._height;

    glViewport(0, 0, width, height);
    GLint linkStatus(0);
    {
		glGetProgramiv(AuxiliaryComiledProgramId, GL_LINK_STATUS, &linkStatus);
        if (GL_FALSE != linkStatus)
        {
			glUseProgram(AuxiliaryComiledProgramId);
			glEnableVertexAttribArray(_position);
			glEnableVertexAttribArray(_color);
        }
        else
        {
            begin();
        }
    }
	



    

    matrix4 screenProj = ortho<float>(0, width, height, 0, -100.0f, 100);
    GLfloat x = 100;
    GLfloat y = 100;
    GLfloat w = 100;
    GLfloat h = 100;

    Vertex ary[] = 
    {
        float2{ x, y },         Rgba4Byte(255, 0, 0, 255),
        float2{ x, y + h },     Rgba4Byte(0, 255, 0, 255),
        float2{ x + w, y },     Rgba4Byte(0, 0, 255, 255),
        float2{ x + w, y + h }, Rgba4Byte(255, 255, 255, 255),
    };

#define USE_MATRIX  1
#if USE_MATRIX == 1
    matrix4 matTransToOrigin;
    matTransToOrigin.translate(-150, -150, 0); // move center to origin.

    static float delta = 0;
    matrix4 matRotate;
    matRotate.rotateZ(delta);
    delta += 1;

    matrix4 matTransback;
    matTransback.translate(150, 150, 0);

    matrix4 matRotateSelf = matTransback * (matRotate * matTransToOrigin);

    screenProj = screenProj * matRotateSelf;
#else
    static float delta = 0;
    delta += 1;
    // rotate according to axis Z, (0, 0).
    quaternion quat = angleAxis(delta, float3(0, 0, 1));
    matrix4 matMVP = makeTransform(float3(0, 0, 0), float3(1, 1, 1), quat);
    screenProj = screenProj * matMVP;
#endif

    glUniformMatrix4fv(_mvp, 1, false, screenProj.data());
    glVertexAttribPointer(_position, 2, GL_FLOAT, false, sizeof( Vertex ), ary);
    glVertexAttribPointer(_color, 4, GL_UNSIGNED_BYTE, true, sizeof( Vertex ), &( ary[0].color ));
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

	
	if (GL_FALSE != linkStatus)
	{
		glDisableVertexAttribArray(_color);
		glDisableVertexAttribArray(_position);
		glUseProgram(0);
	}
	else
	{
        end();
	}
    
}

void RotateRectangle::begin()
{
    glUseProgram(_programId);
    glEnableVertexAttribArray(_position);
    glEnableVertexAttribArray(_color);
}

void RotateRectangle::end()
{
    glDisableVertexAttribArray(_color);
    glDisableVertexAttribArray(_position);
    glUseProgram(0);
}

bool RotateRectangle::init()
{
    _valid = ShaderProgram::initWithFile(_vsFileName, _fsFileName);
    if ( _valid )
    {
        _position = glGetAttribLocation(_programId, "_position");
        _color = glGetAttribLocation(_programId, "_color");
        _mvp = glGetUniformLocation(_programId, "_mvp");
    }
    RunAuxiliaryRHIThread = std::thread(AuxiliaryRHIThread, &AuxiliaryRHIThreadEvent);
    
	{

		std::string     _vertexShaderSrc;
		std::string     _fragShaderSrc;
		bool error(false);
		_vertexShaderSrc = TextReader::readFromFile(vsFileName_mt);
		error = _vertexShaderSrc.empty();
		

		_vertexShaderId_mt = ShaderHelper::compileVertexShader(_vertexShaderSrc);
		error = (_vertexShaderId_mt == 0);
		

		_fragShaderSrc = TextReader::readFromFile(fsFileName_mt);
		error = _fragShaderSrc.empty();
		

		_fragShaderId_mt = ShaderHelper::compileFragmentShader(_fragShaderSrc);
		error = (_fragShaderId_mt == 0);
		
		QuitAuxiliaryRHITask.push_back(InitAuxiliaryOpenGLContext);
		AuxiliaryRHIThreadEvent.Wakeup();
	}
	

    return _valid;
}

RotateRectangle* RotateRectangle::create()
{
    auto * self = new RotateRectangle();
    if ( self && self->init() )
    {
        self->autorelease();
        return self;
    }
    return nullptr;
}

NS_END(elloop);